package com.z.redis.resp;

import com.z.redis.datatype.BytesWrapper;
import io.netty.buffer.ByteBuf;

/**
 * 实现 Redis 服务端的 RESP 协议编解码，支持命令解析与响应生成
 */
public interface Resp {

    /**
     * 将 RESP 响应对象写入到 ByteBuf 缓冲区中
     * @param resp
     * @param buffer
     */
    static void write(Resp resp, ByteBuf buffer) {
        if (resp instanceof SimpleString) { // 处理简单字符串
            buffer.writeByte(RespType.STATUS.getCode()); // 写入状态码 '+'
            String content = ((SimpleString) resp).getContent();
            // 写入内容和终止符 ”\r\n“
            for (char each : content.toCharArray()) {
                buffer.writeByte((byte) each);
            }
            buffer.writeByte(RespType.R.getCode());
            buffer.writeByte(RespType.N.getCode());
        } else if(resp instanceof Errors) { // 处理错误信息
            buffer.writeByte(RespType.ERROR.getCode()); // 写入状态码 '-'
            String content = ((Errors) resp).getContent();
            // 写入内容和终止符 ”\r\n“
            for (char each : content.toCharArray()) {
                buffer.writeByte((byte) each);
            }
            buffer.writeByte(RespType.R.getCode());
            buffer.writeByte(RespType.N.getCode());
        } else if(resp instanceof RespInt) { // 处理整数
            buffer.writeByte(RespType.INTEGER.getCode()); // 写入状态码 ':'
            String content = String.valueOf(((RespInt) resp).getValue());
            // 写入内容和终止符 ”\r\n“
            for (char each : content.toCharArray()) {
                buffer.writeByte((byte) each);
            }
            buffer.writeByte(RespType.R.getCode());
            buffer.writeByte(RespType.N.getCode());
        } else if(resp instanceof BulkString) { // 处理批量字符串（"$5\r\nhello\r\n"）
            buffer.writeByte(RespType.BULK.getCode()); // 写入状态码 '$'
            BytesWrapper content = ((BulkString) resp).getContent();
            if (content == null) {
                buffer.writeByte(RespType.ERROR.getCode());
                buffer.writeByte(RespType.ONE.getCode());
                buffer.writeByte(RespType.R.getCode());
                buffer.writeByte(RespType.N.getCode());
            } else if (content.getByteArray().length == 0) {
                buffer.writeByte(RespType.ZERO.getCode());
                buffer.writeByte(RespType.R.getCode());
                buffer.writeByte(RespType.N.getCode());
                buffer.writeByte(RespType.R.getCode());
                buffer.writeByte(RespType.N.getCode());
            } else {
                String length = String.valueOf(content.getByteArray().length);
                for (char each : length.toCharArray()) {
                    buffer.writeByte((byte) each);
                }
                buffer.writeByte(RespType.R.getCode());
                buffer.writeByte(RespType.N.getCode());
                buffer.writeBytes(content.getByteArray());
                buffer.writeByte(RespType.R.getCode());
                buffer.writeByte(RespType.N.getCode());
            }
        } else if(resp instanceof RespArray) { // 处理数组（"*2\r\n$3\r\nget\r\n$5\r\nkey\r\n"）
            buffer.writeByte(RespType.MULTYBULK.getCode()); // 写入'*'字符
            Resp[] array = ((RespArray) resp).getArray();
            String length = String.valueOf(array.length);
            for(char each : length.toCharArray()) {
                buffer.writeByte((byte) each);
            }
            buffer.writeByte(RespType.R.getCode());
            buffer.writeByte(RespType.N.getCode());
            for (Resp each : array) {
                write(each, buffer);
            }
        } else {
            throw new IllegalArgumentException("Unsupported RESP type");
        }
    }

    /**
     * 将客户端发送的RESP协议字节流反序列化成Redis命令
     * @param buffer
     * @return
     */
    static Resp decode(ByteBuf buffer) {
        if (buffer.readableBytes() <= 0){
            throw new IllegalArgumentException("Incomplete command");
        }
        char c = (char) buffer.readByte();
        if (c == RespType.STATUS.getCode()) { // 简单字符串
            return new SimpleString(getString(buffer));
        } else if(c == RespType.ERROR.getCode()) { // 错误信息
            return new Errors(getString(buffer));
        } else if(c == RespType.INTEGER.getCode()) { // 整数
            int value = getNumber(buffer);
            return new RespInt(value);
        } else if(c == RespType.BULK.getCode()) { // 批量字符串
            int length = getNumber(buffer);
            byte[] content;
            if(length == -1){
                content = null;
            } else {
                content = new byte[length];
                buffer.readBytes(content);
            }
            if (buffer.readByte() != RespType.R.getCode() || buffer.readByte() != RespType.N.getCode()) {
                throw new IllegalStateException("没有读取到完整的命令");
            }
            return new BulkString(new BytesWrapper(content));
        } else if(c == RespType.MULTYBULK.getCode()) { // 数组
            int numOfElement = getNumber(buffer);
            Resp[] array = new Resp[numOfElement];
            for (int i=0;i<numOfElement;i++) {
                array[i]=decode(buffer);  // 递归解析数组元素
            }
            return new RespArray(array);
        } else{
            // 'A'~'Z'
            if (c > 64 && c < 91) {
                return new SimpleString(c + getString(buffer));
            } else {
                return decode(buffer);
            }
        }
    }

    /**
     * 解析 RESP 协议中的数字（如数组长度、批量字符串长度） "100\r\n" → 100，"-1\r\n" → -1
     * @param buf
     * @return
     */
    static int getNumber(ByteBuf buf){
        char c;
        c = (char)buf.readByte();
        boolean negative = false;
        int value = 0;
        // 错误 (Error) 响应的首字节 “-”
        if (c == RespType.ERROR.getCode()) { // 处理负数
            negative = true;
        } else {
            value = c - '0';
        }
        // 直到读到 '\r'
        while (buf.readableBytes() > 0 && (c = (char) buf.readByte()) != RespType.R.getCode()) {
            value = value * 10 + (c - RespType.ZERO.getCode());
        }
        if (buf.readableBytes() == 0 || buf.readByte() != RespType.N.getCode()) {
            throw new IllegalStateException("没有读取到完整的命令");
        }
        return negative ? -value : value;
    }

    /**
     * 解析 RESP 协议中的字符串内容 "hello\r\n" → "hello"
     * @param buffer
     * @return
     */
    static String getString(ByteBuf buffer) {
        char c;
        StringBuilder builder = new StringBuilder();
        while (buffer.readableBytes() > 0 && (c = (char) buffer.readByte()) != RespType.R.getCode()) {
            builder.append(c);
        }
        if (buffer.readableBytes() == 0 || buffer.readByte() != RespType.N.getCode()) {
            throw new IllegalStateException("没有读取到完整的命令");
        }
        return builder.toString();
    }
}
